package gm.server.virtual.simulator2D;

import com.sun.scenario.scenegraph.SGGroup;
import com.sun.scenario.scenegraph.SGShape;
import com.sun.scenario.scenegraph.SGTransform;
import gm.GmLog;
import gm.server.Head;
import gm.server.Nut;
import gm.server.Tip;
import gm.server.WrongPositionException;
import gm.server.geom.Vector2;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;

/**
 * Végpont komponens.
 *
 * @author imruf84
 */
public class TipComponent extends Tip {

    /**
     * Síkidom transzformáció mátrixa.
     */
    final SGTransform.Affine transform = SGTransform.createAffine(null, null);
    /**
     * Transzformáció csoport.
     */
    final SGGroup transformGroup = new SGGroup();
    /**
     * Komponens.
     */
    final SGGroup component = new SGGroup();
    /**
     * Tű sugara.
     */
    private final double needleRadius;
    /**
     * Huzal.
     */
    private final SGShape edges = new SGShape();

    /**
     * Konstruktor.
     *
     * @param nut csavar
     * @param nutDitsance csavartól való távolság
     * @param head fej
     * @param headDistance fejtől való távolság
     * @param needleRadius
     */
    public TipComponent(Nut nut, double nutDitsance, Head head, double headDistance, double needleRadius) {
        super(nut, nutDitsance, head, headDistance);
        this.needleRadius = needleRadius;
        createComponent();
    }

    /**
     * Komponens létrehozása.
     */
    private void createComponent() {

        double nr = getNeedleRadius();

        edges.setFillPaint(new Color(0.0f, 1.0f, 0.0f, 0.8f));
        edges.setAntialiasingHint(RenderingHints.VALUE_ANTIALIAS_ON);
        transformGroup.add(edges);

        SGShape sh = new SGShape();
        sh.setShape(new Ellipse2D.Double(-nr / 2, -nr / 2, nr, nr));
        sh.setFillPaint(new Color(0, 1f, 1f, .85f));
        transformGroup.add(sh);
        sh.setAntialiasingHint(RenderingHints.VALUE_ANTIALIAS_ON);

        transform.setChild(transformGroup);
        component.add(transform);

        getHeadComponent().appendChild(getComponent());

        updateTransform();
    }

    /**
     * Élek frissítése.
     */
    private void updateEdges() {
        try {
            BasicStroke bsEdges = new BasicStroke(0.4f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, null, 0);
            Path2D pathEdges = new Path2D.Double();
            Vector2 tg = calculatePositionGlobal().sub(getHead().calculatePositionGlobal());
            pathEdges.moveTo(-tg.x, -tg.y);

            pathEdges.lineTo(0, 0);
            Vector2 ng = getArm().getNut().calculatePositionGlobal().sub(getHead().calculatePositionGlobal());
            pathEdges.lineTo(ng.x - tg.x, ng.y - tg.y);
            edges.setShape(bsEdges.createStrokedShape(pathEdges));
        } catch (WrongPositionException ex) {
            GmLog.printError(ex);
        }
    }

    /**
     * Transzformáció frissítése.
     */
    private void updateTransform() {
        try {
            AffineTransform t = new AffineTransform();
            t.setToIdentity();
            Vector2 p = calculatePositionGlobal().sub(getHead().calculatePositionGlobal());
            t.translate(p.x, p.y);
            transform.setAffine(t);
            updateEdges();
        } catch (WrongPositionException ex) {
            GmLog.printError(ex);
        }
    }

    /**
     * Pozíció frissítése.
     */
    public void updatePosition() {
        updateTransform();
    }

    /**
     * Komponens lekérdezése.
     *
     * @return komponens
     */
    public SGGroup getComponent() {
        return component;
    }

    /**
     * Beszúrás gyermekként.
     *
     * @param child gyermek
     */
    public void appendChild(SGGroup child) {
        transformGroup.add(child);
    }

    /**
     * Fej komponens lekérdezése.
     *
     * @return fej komponens
     */
    public HeadComponent getHeadComponent() {
        return (HeadComponent) getHead();
    }

    /**
     * Kar komponens lekérdezése.
     *
     * @return kar komponens
     */
    public ArmComponent getArmComponent() {
        return (ArmComponent) getArm();
    }

    /**
     * Tű sugarának a lekérdezése.
     *
     * @return tű sugara
     */
    public double getNeedleRadius() {
        return needleRadius;
    }

}
